﻿namespace NTLib.Pipe.Windows.UTest.Containers
{
    using Core.Descriptors;
    using Core.Reflection;
    using Descriptors;
    using Exceptions;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using Pipe.Descriptors;
    using Pipe.UTest.Containers;
    using Pipe.UTest.TestData;
    using Resources;
    using Streaming.Formats;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Windows.Containers;

    [TestClass]
    public class NamedPipeSourceUTest : Test.Resources.BaseTestClass
    {
        #region Fields

        private readonly PipeSourceUTest<NamedPipeSource<DataStruct>> _tester = new PipeSourceUTest<NamedPipeSource<DataStruct>>();
        private TestPackageFormaterManager _pkg;

        #endregion

        #region Methods

        #region Helper

        /// <summary>
        /// Creates a target descriptor using the <see cref="SimpleJsonPackageFormater"/> as formater
        /// </summary>
        private ITargetDescriptor CreateTargetDescriptor(bool isServer, string name)
        {
            var idFormater = typeof(SimpleJsonPackageFormater).GetId();
            var formaterName = nameof(SimpleJsonPackageFormater);

            var formaterDescriptor = new Descriptor(idFormater, formaterName);
            NamedPipeTargetDescriptor desc = new NamedPipeTargetDescriptor(Guid.NewGuid(),
                                                                           formaterDescriptor,
                                                                           isServer,
                                                                           name);
            return desc;
        }

        /// <summary>
        /// Initializes the u test.
        /// </summary>
        [TestInitialize]
        public void InitUTest()
        {
            this._pkg = new TestPackageFormaterManager();
            this._pkg.Register<SimpleJsonPackageFormater>();
        }

        [TestCleanup]
        public void ReleaseUTestResources()
        {
            if (this._pkg != null)
            {
                this._pkg.Dispose();
            }
        }

        #endregion

        /// <summary>
        /// Test if the <see cref="NamedPipeSource{T}"/> is well initialize with the default values
        /// </summary>
        [TestMethod]
        [TestCategory(TestHelper.CATEGORIE_CONTAINERS)]
        public void NamedPipeSource_CreateAndDispose()
        {
            this._tester.PipeSource_CreateAndDispose();
        }

        /// <summary>
        /// Test if the <see cref="NamedPipeSource{T}"/> is well initialize with the default values
        /// </summary>
        [TestMethod]
        [TestCategory(TestHelper.CATEGORIE_CONTAINERS)]
        public void NamedPipeSource_CreateAndInitialize()
        {
            var pipeName = Guid.NewGuid().ToString();
            var desc = CreateTargetDescriptor(true, pipeName);
            this._tester.PipeSource_CreationAndInit(desc);
        }


        /// <summary>
        /// Test if the <see cref="NamedPipeSource{T}"/> is well initialize with the default values
        /// </summary>
        [TestMethod]
        [TestCategory(TestHelper.CATEGORIE_CONTAINERS)]
        public void NamedPipeSource_CreateFromPoolAndDispose()
        {
            this._tester.PipeSource_CreateFromPoolAndDispose();
        }

        /// <summary>
        /// Test if the <see cref="NamedPipeSource{T}"/> is well initialize with the default values
        /// </summary>
        [TestMethod]
        [TestCategory(TestHelper.CATEGORIE_CONTAINERS)]
        public void NamedPipeSource_CreateFromPoolAndInitialize()
        {
            var pipeName = Guid.NewGuid().ToString();
            var desc = CreateTargetDescriptor(true, pipeName);
            this._tester.PipeSource_CreationFromPoolAndInit(desc);
        }

        /// <summary>
        /// Test if we can push and pop through the pipe
        /// </summary>
        [TestMethod]
        [TestCategory(TestHelper.CATEGORIE_CONTAINERS)]
        public void NamedPipeSource_SendAndPop()
        {
            var timeout = base.CreateTimeout(10);

            var pipeName = Guid.NewGuid().ToString();
            var desc = CreateTargetDescriptor(true, pipeName);
            var descTarget = CreateTargetDescriptor(false, pipeName);

            using (var sourcePipe = new NamedPipeSource<DataStruct>())
            {
                Assert.AreEqual(PipeStatus.NotInitialize, sourcePipe.Status);

                sourcePipe.InitializeAsync(desc, PipeType.TwoWay).Wait(timeout.Token);

                Assert.AreEqual(PipeStatus.Ready, sourcePipe.Status);

                using (var targetPipe = new NamedPipeSource<DataStruct>())
                {
                    Assert.AreEqual(PipeStatus.NotInitialize, targetPipe.Status);

                    targetPipe.InitializeAsync(descTarget, PipeType.TwoWay).Wait(timeout.Token);

                    Assert.AreEqual(PipeStatus.Ready, sourcePipe.Status);
                    Assert.AreEqual(PipeStatus.Ready, targetPipe.Status);

                    string data = Guid.NewGuid().ToString();

                    DataStruct structOrigin = new DataStruct();
                    structOrigin.Data = data;

                    sourcePipe.SendItemAsync(structOrigin).Wait(timeout.Token);

                    var resultTask = targetPipe.DequeueItemAsync(timeout.Token);
                    resultTask.Wait(timeout.Token);

                    var structResult = resultTask.Result;

                    Assert.IsNotNull(structResult);
                    Assert.IsFalse(object.ReferenceEquals(structOrigin, structResult));
                    Assert.AreEqual(structOrigin.Data, structResult.Data);
                }

                Task.Delay(TimeSpan.FromSeconds(2)).Wait(timeout.Token);

                //Assert.AreEqual(PipeStatus.NotInitialize, sourcePipe.Status);
            }
        }

        #endregion
    }
}
